package com.mate.cloud.auth.handler;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 登录尝试次数限制
 * @author:         MI
 * @email:          448341911@qq.com
 * @createTime:     2025/6/5 16:54
 * @updateUser:     MI
 * @updateTime:     2025/6/5 16:54
 * @updateRemark:   修改内容
 * @version:        1.0
 */
@Slf4j
@Component
public class CustomAuthenticationFailureHandler2 implements AuthenticationFailureHandler {

    /** 使用内存存储登录尝试次数（实际项目中建议使用Redis等分布式缓存） */
    private static final Map<String, Integer> loginAttempts = new ConcurrentHashMap<>();
    /** 最大允许连续登陆失败的次数 */
    private static final int MAX_ATTEMPTS = 3;

//    @Autowired
//    private ObjectMapper objectMapper;
//

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("onAuthenticationFailure 登陆失败");
        // 获取用户名（如果有）
        String username = request.getParameter("userName");
        // 记录登录失败日志
        System.err.println("用户 '" + username + "' 登录失败: " + exception.getMessage());

        String errorMessage = "";
        if(!StringUtils.hasText(username)) {
            errorMessage = "用户名/密码不能为空";
            sendRedirect(request, response, username, errorMessage);
            return;
        }
        // 处理登录尝试次数
        if (StringUtils.hasText(username)) {
            loginAttempts.put(username, loginAttempts.getOrDefault(username, 0) + 1);
            if (loginAttempts.get(username) >= MAX_ATTEMPTS) {
                // 锁定账户逻辑（这里仅示例，实际应更新数据库）
                errorMessage = "由于多次登录失败，账户已被锁定";
            }
        }
        if(!StringUtils.hasText(errorMessage)) {
            errorMessage = getErrorMessage(exception, username);
        }
        sendRedirect(request, response, username, errorMessage);

    }
    private void sendRedirect(HttpServletRequest request, HttpServletResponse response, String username,
                              String errorMessage) throws IOException {
        // 将错误信息和剩余尝试次数存储到session中
        HttpSession session = request.getSession();
        session.setAttribute("errorMessage", errorMessage);
        if (StringUtils.hasText(username) && loginAttempts.containsKey(username)) {
            session.setAttribute("remainingAttempts", MAX_ATTEMPTS - loginAttempts.get(username));
        }

        // 重定向到登录页面
        response.sendRedirect(request.getContextPath() + "/login?error");
    }

    // 根据不同的异常类型返回不同的错误信息
    private String getErrorMessage(AuthenticationException exception,String userName) {
        if (exception instanceof BadCredentialsException) {
            int attempts = loginAttempts.getOrDefault(userName, 0);
            int remaining = MAX_ATTEMPTS - attempts;
            if (remaining > 0) {
                return "用户名或密码错误，您还剩" + remaining + "次尝试机会";
            } else {
                return "由于多次登录失败，账户已被锁定";
            }
        } else if (exception instanceof LockedException) {
            return "账户已被锁定，请联系管理员";
        } else if (exception instanceof DisabledException) {
            return "账户已被禁用，请联系管理员";
        } else if (exception instanceof AccountExpiredException) {
            return "账户已过期，请联系管理员";
        } else if (exception instanceof CredentialsExpiredException) {
            return "密码已过期，请重置密码";
        } else {
            return "登录失败，请稍后再试";
        }
    }


    /**
     * 在登录成功时重置尝试次数
     * @param username
     */
    public static void resetAttempts(String username) {
        if (username != null) {
            loginAttempts.remove(username);
        }
    }
}
